/*********************************************************************************
    L1 cache unit for PRV5xx processor
    //input cache interface
    //output BIU interface
    // 128Bit I/O 
    // |-----------------------------------------|-----------(IN ENTRY)------------|
    // |----------TAG(29Bit)---|---INDEX(5Bit)---|---LINE(2Bit)---|---DUMY(4bit)---|
*********************************************************************************/
`include "PRV564Config.v"
`include "PRV564Define.v"
`define LSU_AMOCMD 8'b0010_????
module L1D
#(
    parameter   SRAM_BANKCOEFF=2,
                SRAM_BANKNUM=2**SRAM_BANKCOEFF,
                CACHE_DEPTH=SRAM_BANKNUM*64, //4 Bank * 64 RAM Depth * 16 Byte
                WAY_NUM=2,
                INDEX_DEPTH=CACHE_DEPTH/WAY_NUM/4,
                CACHE_FIBID=8'h01
)
(
    input  wire             GLB_CLKi,
    input  wire             GLB_RSTi,                      //Cache冲刷请求
    //Access Queue
    input  wire             AQ_V,
    input  wire [7:0]       AQ_ID,
    input  wire [7:0]       AQ_CMD,
    input  wire [15:0]      AQ_BSEL,
    input  wire             AQ_CI,
    input  wire             AQ_WT,
    input  wire [127:0]     AQ_WDATA,
    input  wire [`PADR-1:0] AQ_ADDR,
    output wire             AQ_FULL,
    //Respond Queue
    output reg              RQ_V,
    output reg  [7:0]       RQ_ID,
    output wire             RQ_WRERR,
    output wire             RQ_RDERR,
    output wire             RQ_RDY,
    output wire [127:0]     RQ_RDATA,
    input  wire             RQ_ACK,
    //To FIB
    output L1_FIBo_REQ,
    output L1_FIBo_WREN,
    output [7:0] L1_FIBo_ID,
    output [7:0] L1_FIBo_CMD,
    output [3:0] L1_FIBo_BURST,
    output [3:0] L1_FIBo_SIZE,
    output [`PADR-1:0] L1_FIBo_ADDR,
    output [`XLEN-1:0] L1_FIBo_DATA,
    // slave reply
    input L1_FIBi_ACK,
    input L1_FIBi_FULL,
    input L1_FIBi_V,
    input[7:0] L1_FIBi_ID,
    input[7:0] L1_FIBi_RPL,
    input[`XLEN-1:0] L1_FIBi_DATA
    
);
localparam INDEX_WIDTH=$clog2(INDEX_DEPTH);
localparam TAG_WIDTH=`PADR-INDEX_WIDTH-6;
localparam MEM_ADDRWID=$clog2(CACHE_DEPTH);
localparam WAYADDR_WID = $clog2(WAY_NUM);

localparam FSM_IDLE = 4'h0;//Normal Operation
localparam FSM_FILL = 4'h1;//bulk cache refill
localparam FSM_SGRL = 4'h2;//single read low 64b
localparam FSM_SGRH = 4'h3;//single read high 64b
localparam FSM_WBAK = 4'h4;//bulk write back
localparam FSM_SGWL = 4'h5;//single write low 64b
localparam FSM_SGWH = 4'h6;//single write high 64b
localparam FSM_FNCE = 4'h7;//do fence check
localparam FSM_RTOW = 4'h8;//TODO Reconstruct BIU-L1 handshake in order to remove this
localparam FSM_WTOR = 4'h9;
localparam FSM_AMOC = 4'hA;

//AQ FIFO OUTPUT
wire             AQo_V;
wire [7:0]       AQo_ID;
wire [7:0]       AQo_CMD;
wire [15:0]      AQo_BSEL;
wire             AQo_CI;
wire             AQo_WT;
wire [127:0]     AQo_WDATA;
wire [`PADR-1:0] AQo_ADDR;
wire             AQo_FREE;
reg              CMD_FINISH;
L1_AQBuf #(.L1IBUF(1'b0))
L1D_AQBuf(
    .GLB_CLKi(GLB_CLKi),
    .GLB_RSTi(GLB_RSTi),      
    .AQi_V(AQ_V),
    .AQi_ID(AQ_ID),
    .AQi_CMD(AQ_CMD),
    .AQi_BSEL(AQ_BSEL),
    .AQi_CI(AQ_CI),
    .AQi_WT(AQ_WT),
    .AQi_WDATA(AQ_WDATA),
    .AQi_ADDR(AQ_ADDR),
    .AQi_FULLo(AQ_FULL),

    .AQo_V(AQo_V),
    .AQo_ID(AQo_ID),
    .AQo_CMD(AQo_CMD),
    .AQo_BSEL(AQo_BSEL),
    .AQo_CI(AQo_CI),
    .AQo_WT(AQo_WT),
    .AQo_WDATA(AQo_WDATA),
    .AQo_ADDR(AQo_ADDR),
    .AQo_FREE(AQo_FREE)

);

wire Pipe_Stall;
assign AQo_FREE=!Pipe_Stall & CMD_FINISH;
reg [3:0]state,state_next;
reg [127:0]Cacheless_Buffer;
wire TagFlush,CacheAccess,CacheWB,CacheWT;
wire line_miss,cacheram_rdy,write;

reg Cache_CI,Cache_V;

assign Pipe_Stall=(RQ_V & !RQ_ACK) | !(Cache_CI | cacheram_rdy);
//BIU 2 Cache interface
reg bus_seq_read,bus_single_read;
reg bus_seq_write,bus_single_write;
wire [`PADR-1:0]bus_access_addr;
wire [TAG_WIDTH-1:0]wbak_tag;
wire [2:0]bus_seq_cnt;
wire [63:0]bus_data_read;
reg  [63:0]bus_data_write;
wire bus_datavalid;
wire bus_finished;
wire bus_error;
wire dirty_comp;
wire [3:0]req_size;
wire [3:0]req_bsel;
wire [3:0]bsel_enc;
wire [127:0]bufwr_bsel;
reg do_fence,amo_opreq;
wire replace_dirty;


always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        state<=FSM_IDLE;
    else 
        state<=state_next;
//Main FSM state transfer        
always@(*)
    case(state)
        FSM_IDLE:
        begin
            if(AQo_V)
                casez ({AQo_CI,AQo_WT,line_miss,AQo_CMD})
                    {3'b???,`LSU_NOP}:
                        state_next=FSM_IDLE;
                    {3'b0?0,`LSU_READ}:  //Cache Normal read_0000_0010
                        state_next=FSM_IDLE;    
                    {3'b000,`LSU_WRITE}:  //Cache Normal write_0000_0011
                        state_next=FSM_IDLE;     
                    {3'b1??,`LSU_READ}: //Cacheless read_0000_0010
                        if(AQo_BSEL[7:0]==0)state_next=FSM_SGRH;
                        else state_next=FSM_SGRL;
                    {3'b1??,`LSU_WRITE}: //Cacheless write_0000_0011
                        if(AQo_BSEL[7:0]==0)state_next=FSM_SGWH;
                        else state_next=FSM_SGWL;
                    {3'b0?1,`LSU_READ}: //Cache miss read_0000_0010
                        if(replace_dirty)state_next=FSM_WBAK;
                        else state_next=FSM_FILL;
                    {3'b0?1,`LSU_WRITE}: //Cache miss write_0000_0011
                        if(replace_dirty)state_next=FSM_WBAK;
                        else state_next=FSM_FILL;
                    {3'b010,`LSU_WRITE}: //Cache write through_0000_0011
                        if(AQo_BSEL[7:0]==0)state_next=FSM_SGWH;
                        else state_next=FSM_SGWL;
                    {3'b?0?,`LSU_CacheRef}://Flush_0000_0111
                        state_next=FSM_FNCE;
                    {3'b?1?,`LSU_CacheRef}://Flush_0000_0111
                        state_next=FSM_IDLE;
                    {3'b???,`LSU_AMOCMD}://Cache Hit
                        if((!AQ_CI) & dirty_comp & (!line_miss))
                            state_next=FSM_FNCE;// and line dirty
                        else
                            case(AQo_CMD)
                                `LSU_READ_Lock:
                                    if(AQo_BSEL[7:0]==0)state_next=FSM_SGRH;
                                    else state_next=FSM_SGRL;
                                `LSU_WRITE_Unloc:
                                    if(AQo_BSEL[7:0]==0)state_next=FSM_SGWH;
                                    else state_next=FSM_SGWL;
                                default: state_next=FSM_AMOC;
                            endcase
                    default: 
                    begin
                        state_next=FSM_IDLE;
                        $display("ERROR: Cache UNDEFINED INPUT ENCOUNTERED!");
                    end
                endcase
            else
                state_next=FSM_IDLE;
        end
        FSM_FILL:
        begin
            if(bus_finished)
                if(AQo_WT & AQo_CMD==`LSU_WRITE)//
                    state_next = FSM_RTOW;
                else state_next=FSM_IDLE;
            else 
                state_next=FSM_FILL;
        end
        FSM_SGRH:
        begin
            if(bus_finished)
                state_next=FSM_IDLE;
            else 
                state_next=FSM_SGRH;
        end
        FSM_SGRL:
        begin
            if(bus_finished)
                if(AQo_BSEL[15:8]==0)
                    state_next=FSM_IDLE;
                else 
                    state_next=FSM_SGRH;
            else 
                state_next=FSM_SGRL;
        end
        FSM_WBAK:
        begin
            if(bus_finished)
                if(do_fence)
                    state_next=FSM_FNCE;
                else 
                    state_next=FSM_WTOR;
            else state_next=FSM_WBAK;
        end
        FSM_SGWH:
        begin
            if(bus_finished)
                state_next=FSM_IDLE;
            else
                state_next=FSM_SGWH;
        end
        FSM_SGWL:
        begin
            if(bus_finished)
                if(AQo_BSEL[15:8]==0)
                    state_next=FSM_IDLE;
                else 
                    state_next=FSM_SGWH;
            else state_next=FSM_SGWL;
        end
        FSM_FNCE:
        begin
            if(replace_dirty & (!AQ_WT))
                state_next=FSM_WBAK;
            else if(AQo_CMD[7:4]==4'h2)
                case(AQo_CMD)
                    `LSU_READ_Lock:
                        if(AQo_BSEL[7:0]==0)state_next=FSM_SGRH;
                        else state_next=FSM_SGRL;
                    `LSU_WRITE_Unloc:
                        if(AQo_BSEL[7:0]==0)state_next=FSM_SGWH;
                        else state_next=FSM_SGWL;
                    default: state_next=FSM_AMOC;
                endcase
            else state_next=FSM_IDLE; 
        end
        FSM_AMOC:
        begin
            if(bus_finished)
                state_next=FSM_IDLE;
            else
                state_next=FSM_AMOC;
        end
        FSM_RTOW:
        begin
            if(!bus_finished)
                if(AQo_BSEL[7:0]==0)state_next=FSM_SGWH;
                else state_next=FSM_SGWL;
            else
                state_next=FSM_RTOW;
        end
        FSM_WTOR:
        begin
            if(!bus_finished)
                state_next=FSM_FILL;
            else
                state_next=FSM_WTOR;
        end
        default:
            state_next=FSM_IDLE;
    endcase
//COMMAND FINISH BLOCK    
always@(*)// TODO: debug fence writeback
    casez({AQo_CI,AQo_WT,line_miss,AQo_CMD})
        {3'b0??,`LSU_READ},//Cached read OK
        {3'b00?,`LSU_WRITE}:
            CMD_FINISH=(state_next == FSM_IDLE) & (state == FSM_IDLE);
        {3'b01?,`LSU_WRITE},
        {3'b1??,`LSU_READ},
        {3'b1??,`LSU_WRITE},
        {3'b???,`LSU_CacheRef},
        {3'b???,`LSU_AMOCMD}:
            CMD_FINISH=(state_next == FSM_IDLE);
        {3'b???,`LSU_NOP}:
            CMD_FINISH=1'b1;
        default:
            CMD_FINISH=1'b1;
    endcase
//fence blk
always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        do_fence<=1'b0;
    else if(state_next==FSM_FNCE)
        do_fence<=1'b1;
    else if(state_next==FSM_IDLE)
        do_fence<=1'b0;
    else
        do_fence<=do_fence;
//Bus Seq Read req        
always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        bus_seq_read<=0;
    else if (state_next==FSM_FILL)
        bus_seq_read<=1'b1;
    else
        bus_seq_read<=0;
//Bus Seq write req
always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        bus_seq_write<=0;
    else if (state_next==FSM_WBAK)
        bus_seq_write<=1'b1;
    else
        bus_seq_write<=0;
//Bus single read req
always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        bus_single_read<=0;
    else 
    case(state_next)
        FSM_SGRH:
        begin
            if(state == FSM_SGRL)
                bus_single_read<=1'b0;
            else bus_single_read<=1'b1;

        end
        FSM_SGRL:
            bus_single_read<=1'b1;
        default:
            bus_single_read<=0;
    endcase
//Bus single write req  
always@(posedge GLB_CLKi or posedge GLB_RSTi)
    if(GLB_RSTi)
        bus_single_write<=0;
    else 
    case(state_next)
        FSM_SGWH:
            if(state == FSM_SGWL)bus_single_write<=1'b0;
            else bus_single_write<=1'b1;
        FSM_SGWL:
            bus_single_write<=1'b1;
        default:
            bus_single_write<=0;
    endcase
//AMO operation Request
always@(posedge GLB_CLKi or posedge GLB_RSTi)    
    if(GLB_RSTi)
        amo_opreq<=1'b0;
    else if(AQo_V)
        amo_opreq<=(AQo_CMD[7:4]==4'h2);
    else if(state_next == FSM_IDLE)
        amo_opreq<=1'b0;
    else
        amo_opreq<=amo_opreq;


//Cache Inhibited Buffer Block
wire [127:0]CLB_WrDat;
wire CLB_WrCond;
assign CLB_WrCond=AQo_CI & bus_finished &((state==FSM_SGRH)|(state==FSM_SGRL));
assign CLB_WrDat=({bus_data_read,bus_data_read} & bufwr_bsel) | (Cacheless_Buffer & (~bufwr_bsel));  
always@(posedge GLB_CLKi)//Cacheless buffer blk
    if(CLB_WrCond)
        Cacheless_Buffer<=CLB_WrDat;
    else 
        Cacheless_Buffer<=Cacheless_Buffer;
//BSEL_Hold block
reg [15:0]BSEL_Hold;
wire BSEL_Hold_Trig;
assign BSEL_Hold_Trig=  (state_next == FSM_SGRL) | 
                        ((state_next == FSM_SGRH) & (state !=FSM_SGRL)) |
                        (state_next == FSM_SGWL) | 
                        ((state_next == FSM_SGWH) & (state !=FSM_SGWL));
always@(posedge GLB_CLKi)
    if(BSEL_Hold_Trig)
        BSEL_Hold<=AQo_BSEL;
    else 
        BSEL_Hold<=BSEL_Hold;
//---------------------Cache Hit选择---------------------------------
wire [INDEX_WIDTH+3:4]index_addr;//Low word neglected
wire [INDEX_WIDTH-1:0]dirty_index;
wire [TAG_WIDTH-1:0]tag_addr;
wire [1:0]entry_addr;
assign write=(AQo_CMD == `LSU_WRITE);
assign CacheAccess=((AQo_CMD==`LSU_READ) & (!AQo_CI)) | (AQo_CMD[7:4]==4'h2);
assign CacheWT=(!AQo_CI) & AQo_WT & write;
assign CacheWB=(!AQo_CI) & (!AQo_WT) & write;
assign TagFlush=(state==FSM_FNCE) & (state_next == FSM_IDLE)|
                ((AQo_CMD==`LSU_CacheRef) & AQo_WT);

assign index_addr=AQo_ADDR[INDEX_WIDTH+5:6];
assign tag_addr=AQo_ADDR[`PADR-1:INDEX_WIDTH+6];
assign entry_addr=AQo_ADDR[5:4];

wire [MEM_ADDRWID-1:0]CacheAccessAddr;
wire [MEM_ADDRWID-1:0]BusMemAddr;

wire [2:0]bcnt_p1;
assign bcnt_p1=(bus_seq_cnt+L1_FIBo_REQ);
generate if(WAY_NUM>1)
begin : WAY_ASSOCIATIVE
    wire [WAYADDR_WID-1:0]WayReplace_Addr,WayAccess_addr;
    tagman_wa#(//THIS NEEDS TO SYNC WITH DM MANs
        .WAY_DEPTH(INDEX_DEPTH), //How many entries does 1 way have?
        .WAY_NUM(WAY_NUM),//MUST > 1
        .TAG_WID(TAG_WIDTH),
        .WBACK_ENABLE(1'b1) //this actually heavily depends on optimization
    )
    TAG_MANAGER_L1D(
        .clk(GLB_CLKi),
        .rst(GLB_RSTi),
        //Core interface
        .entry_read(CacheAccess),   
        .entry_wthru(CacheWT),
        .entry_wback(CacheWB),
        .address_tag(tag_addr),
        .address_index(index_addr),	
        .dfence_en(do_fence),//start mem sync
        .valid_clear(TagFlush), //flush
        .fill_finish((state == FSM_FILL) & bus_finished), //cachemem write(), confirm refill valid
        .writeback_ok((state == FSM_WBAK) & bus_finished),//data block write back complete(), from cache BU
        .line_miss(line_miss),//refill request
        .replace_dirty(replace_dirty), //page dirty(), need to write back first
        .dirty_comp(dirty_comp),
        .dirty_index(dirty_index),
        .way_dirty_addr(wbak_tag),//When D Fence / replace dirty, the address of valid dirty line to write back
        .way_replace_addr(WayReplace_Addr), //for replace select& dirty flush select
        .way_access_addr(WayAccess_addr)//addr for access 
    );
    assign CacheAccessAddr={WayAccess_addr,index_addr,entry_addr};
    assign BusMemAddr=(bus_seq_write)?{WayReplace_Addr,dirty_index,bcnt_p1[2:1]} : {WayReplace_Addr,dirty_index,bus_seq_cnt[2:1]};
end
else
begin : DIRECT_MAPPED
    tagman_dm #(
        .WAY_DEPTH(INDEX_DEPTH),
        .TAG_WID(TAG_WIDTH),//1K per page
        .WBACK_ENABLE(1'b1) //this actually heavily depends on optimization
    )TAGMAN_DM
    (
        .clk(GLB_CLKi),
        .rst(GLB_RSTi),
        //Core interface
        .entry_read(CacheAccess),   
        .entry_wthru(CacheWT),
        .entry_wback(CacheWB),
        .address_tag(tag_addr),
        .address_index(index_addr),	
        .valid_clear(TagFlush), //flush
        .dfence_en(do_fence),//start mem sync

        .fill_finish((state == FSM_FILL) & bus_finished), //cachemem write(), confirm refill valid
        .writeback_ok((state == FSM_WBAK) & bus_finished),//data block write back complete(), from cache BU
        .line_miss(line_miss),
        .replace_dirty(replace_dirty), //page dirty(), need to write back first
        .writeback_addr(wbak_tag),//When D Fence, the address of valid dirty line to write back
        .writeback_index(dirty_index)
    );
    assign dirty_comp=replace_dirty;
    assign CacheAccessAddr={index_addr,entry_addr};
    assign BusMemAddr= (bus_seq_write)?{dirty_index,bcnt_p1[2:1]}:{dirty_index,bus_seq_cnt[2:1]};
end
endgenerate


wire Cache_FlowCond;
reg  [7:0]Cache_ID;
assign Cache_FlowCond=AQo_V & CMD_FINISH;

reg  [MEM_ADDRWID-1:0] PipeMemAddr_reg,PipeMemAddr_hold;
wire [MEM_ADDRWID-1:0] PipeMemAddr;
reg  [127:0]PipeMemDi;
reg  PipeMemWe;
reg  [15:0]PipeMemBsel;
assign PipeMemAddr=(RQ_V & !RQ_ACK)?PipeMemAddr_hold:PipeMemAddr_reg;

//Memory Stage
always@(posedge GLB_CLKi or posedge GLB_RSTi)//Valid 传递 
begin
    if(GLB_RSTi)
        Cache_V <=1'b0;
    else if(Pipe_Stall)
        Cache_V <=Cache_V;    
    else 
        Cache_V <=Cache_FlowCond;
end
//CI/ID block
always@(posedge GLB_CLKi or posedge GLB_RSTi)
begin
    if(GLB_RSTi)
    begin
        Cache_ID <=0;
        Cache_CI <=0;
    end
    else if(Pipe_Stall | !Cache_FlowCond)//(state_next!=FSM_IDLE)!Cache_VPipe_Stall | 
    begin   
        Cache_ID <=Cache_ID;
        Cache_CI <=Cache_CI;
    end
    else 
    begin
        Cache_ID <=AQo_ID;
        Cache_CI <=AQo_CI | amo_opreq;
    end
        
end
//Memory Address block
always@(posedge GLB_CLKi)
begin
    if( Pipe_Stall | !Cache_FlowCond)
    begin
        PipeMemAddr_reg  <=PipeMemAddr_reg;
        PipeMemAddr_hold <=PipeMemAddr_hold;
    end
    else 
    begin   
        PipeMemAddr_reg  <=CacheAccessAddr;
        PipeMemAddr_hold <=PipeMemAddr_reg;
    end
end
//WE 传递 
always@(posedge GLB_CLKi or posedge GLB_RSTi)
begin
    if(GLB_RSTi)
    begin
        PipeMemWe <=1'b0;
    end
    else if(Pipe_Stall)
    begin
        PipeMemWe <= PipeMemWe;
    end
    else 
    begin
        PipeMemWe <=(CacheWT | CacheWB) & Cache_FlowCond;//Normal Write Back
    end
end
//写数据/BSEL传递
always@(posedge GLB_CLKi)
begin
    if( Pipe_Stall | (!Cache_FlowCond))
    begin
        PipeMemDi  <=PipeMemDi;
        PipeMemBsel<=PipeMemBsel;
    end
    else
    begin   
        PipeMemDi<=AQo_WDATA;
        PipeMemBsel<=AQo_BSEL;
    end

end

wire [127:0]PipeMemDo;
wire [127:0]BusMemDi,BusMemDo;
wire BusMemWe;
wire [15:0]BusMemBsel;

assign BusMemDi= {bus_data_read,bus_data_read};
assign BusMemBsel= ((bus_seq_cnt[0])?16'hff00:16'h00ff);
assign BusMemWe = ((state == FSM_FILL) & bus_datavalid);//When Fill


`ifdef YSYX

    wire [SRAM_BANKCOEFF-1:0]sram_pipebank,sram_busbank;
    wire [5:0]sram_pipeaddr,sram_busaddr;
    assign sram_pipebank=PipeMemAddr[SRAM_BANKCOEFF+1:2];
    assign sram_pipeaddr={PipeMemAddr[MEM_ADDRWID-1:SRAM_BANKCOEFF+2],PipeMemAddr[1:0]};
    assign sram_busbank=BusMemAddr[SRAM_BANKCOEFF+1:2];
    assign sram_busaddr={BusMemAddr[MEM_ADDRWID-1:SRAM_BANKCOEFF+2],BusMemAddr[1:0]};
    pTDPRAM_ysyx #(.BANK_COEFF(SRAM_BANKCOEFF))
    CACHE_MEMORY(
        .addr_A(sram_pipeaddr),
        .bank_A(sram_pipebank),
        .ce_A(Cache_V),//state_next==FSM_IDLE
        .wbsel_A(PipeMemBsel&{16{PipeMemWe}}),
        .opvalid_A(cacheram_rdy),
        .dato_A(PipeMemDo),
        .dati_A(PipeMemDi),

        .addr_B(sram_busaddr),
        .bank_B(sram_busbank),
        .ce_B(state!=FSM_IDLE),
        .wbsel_B(BusMemBsel&{16{BusMemWe}}),
        .opvalid_B(),
        .dato_B(BusMemDo),
        .dati_B(BusMemDi),

        .clk(GLB_CLKi),
        .rst(GLB_RSTi)
    );
`else
    cachemem_dp #(
        .datawidth(128),
        .cache_depth(SRAM_BANKCOEFF*16))
    CACHE_MEMORY(
        .addr_A(PipeMemAddr),
        .addr_B(BusMemAddr),
        .di_A(PipeMemDi),
        .di_B(BusMemDi),
        .we_A(PipeMemWe),
        .we_B(BusMemWe),
        .bsel_A(PipeMemBsel),
        .bsel_B(BusMemBsel),
        .dato_A(PipeMemDo),
        .dato_B(BusMemDo),
        .clk_A(GLB_CLKi),
        .clk_B(GLB_CLKi)
    );
    assign cacheram_rdy=1'b1;
`endif

assign RQ_RDATA=(Cache_CI)?Cacheless_Buffer:PipeMemDo;

always@(posedge GLB_CLKi or posedge GLB_RSTi)
begin
    if(GLB_RSTi)
    begin
        RQ_V <=0;     
        RQ_ID    <=0;
    end
    else if(Pipe_Stall)//(state_next!=FSM_IDLE)
    begin   
        RQ_V <=RQ_V;     
        RQ_ID    <=RQ_ID;
    end
    else 
    begin  //current no istruction stall, keep on going
        RQ_V         <=Cache_V ;
        RQ_ID        <=Cache_ID;
    end
end
assign bufwr_bsel={
        {8{BSEL_Hold[15]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[14]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[13]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[12]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[11]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[10]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[9]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[8]&(state==FSM_SGRH)}},
        {8{BSEL_Hold[7]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[6]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[5]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[4]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[3]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[2]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[1]&(state==FSM_SGRL)}},
        {8{BSEL_Hold[0]&(state==FSM_SGRL)}}
                };
assign bsel_enc=log_cnt8(((state_next==FSM_SGRH)|(state_next==FSM_SGWH))?BSEL_Hold[15:8]:BSEL_Hold[7:0]);
assign req_size=(bus_seq_read | bus_seq_write)?4'h3:4'h0;
assign req_bsel=(bus_seq_read | bus_seq_write | (bus_single_read & `AXI_DIFF))?4'h3:bsel_enc;    //TODO remove this before take off
assign bus_access_addr=(state_next==FSM_WBAK)?
                            ((do_fence)?{wbak_tag,dirty_index,6'h00}:{wbak_tag,index_addr,6'h00}):
                        (AQo_ADDR[`PADR-1:0]&{{`PADR-6{1'b1}},{6{state_next!=FSM_FILL}}});
reg bcnt_hold;

always@(posedge GLB_CLKi)
    bcnt_hold<=bcnt_p1[0];
always@(*)
    case(state_next)
        FSM_FNCE,
        FSM_WBAK:
            bus_data_write = (bcnt_hold)?BusMemDo[127:64]:BusMemDo[63:0];
        FSM_SGWH:
            bus_data_write = AQo_WDATA[127:64];
        FSM_SGWL:
            bus_data_write = AQo_WDATA[63:0];
        default:
            bus_data_write = 64'h0000_010A_9FC7_0042;
    endcase
    // slave reply
FIB_BIU_L1D #(.FIBID(CACHE_FIBID)) BIU (
    .GLBi_CLK(GLB_CLKi),
    .GLBi_ARST(GLB_RSTi),
    .BIUo_WREN(L1_FIBo_WREN),
    .BIUo_REQ(L1_FIBo_REQ),
    .BIUo_ID(L1_FIBo_ID),
    .BIUo_CMD(L1_FIBo_CMD),
    .BIUo_BURST(L1_FIBo_BURST),
    .BIUo_SIZE(L1_FIBo_SIZE),
    .BIUo_ADDR(L1_FIBo_ADDR[`PADR-1:0]),
    .BIUo_DATA(L1_FIBo_DATA),
    .BIUi_FULL(L1_FIBi_FULL),
    .BIUi_V(L1_FIBi_V),
    .BIUi_ACK(L1_FIBi_ACK),
    .BIUi_ID(L1_FIBi_ID),
    .BIUi_RPL(L1_FIBi_RPL),
    .BIUi_DATA(L1_FIBi_DATA),
    //Cache Controller Interface
    .single_write_req(bus_single_write),	//请求单次写（写穿）
    .seq_write_req(bus_seq_write),	//请求写回
    .single_read_req(bus_single_read),			//请求读一次
    .seq_read_req(bus_seq_read),		//请求读一行
    .amo_cmd(AQo_CMD),
    .amo_req(amo_opreq),
    .seq_size(req_size),
    .req_bsel(req_bsel),
    .bus_addr(bus_access_addr),		
    .bus_wdata(bus_data_write),
    .bus_rdata(bus_data_read),
    .addr_count(bus_seq_cnt),
    .data_valid(bus_datavalid),			//cache写
    .trans_error(bus_error),
    .bus_trans_finish(bus_finished)			//传输完成
);

function [3:0]log_cnt8;
 input [7:0]datain;
   integer x;
    reg [1:0]as1[3:0];
    reg [2:0]as2[1:0];
    reg [3:0]as3;
    begin
    for (x=0;x<4;x=x+1)
        as1[x]=datain[2*x+1]+datain[2*x];
    for (x=0;x<2;x=x+1)
        as2[x]=as1[2*x+1]+as1[2*x];
    as3=as2[0]+as2[1];
    log_cnt8=(as3[3] | as3[2:0]>3'h4 )? 4'h3:
    (as3[2] | as3[1:0] > 2'h2)?4'h2:
    (as3[1])?4'h1:4'h0;
    end
endfunction

assign RQ_RDY=1'b1;
assign RQ_RDERR= (state != FSM_IDLE)& bus_error;
assign RQ_WRERR=(state == FSM_SGWH | state_next == FSM_SGWL | state_next == FSM_WBAK) & bus_error;
endmodule



